/**
 * Licensed under the Artistic License; you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * 
 * http://displaytag.sourceforge.net/license.html
 * 
 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

package org.displaytag.filter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.displaytag.tags.TableTag;
import org.displaytag.tags.TableTagParameters;

/**
 * Actually writes out the content of the wrapped response. Used by the j2ee
 * filter and the Spring interceptor implementations.
 * 
 * @author Fabrizio Giustina
 * @version $Revision: 871 $ ($Author: fgiust $)
 */
public final class ExportDelegate {

	/**
	 * logger.
	 */
	private static Log	log	= LogFactory.getLog(ExportDelegate.class);

	/**
	 * Actually writes exported data. Extracts content from the Map stored in
	 * request with the <code>TableTag.FILTER_CONTENT_OVERRIDE_BODY</code>
	 * key.
	 * 
	 * @param wrapper
	 *            BufferedResponseWrapper implementation
	 * @param response
	 *            HttpServletResponse
	 * @param request
	 *            ServletRequest
	 * @throws IOException
	 *             exception thrown by response writer/outputStream
	 */
	protected static void writeExport(HttpServletResponse response,
			ServletRequest request, BufferedResponseWrapper wrapper)
			throws IOException {

		if (wrapper.isOutRequested()) {
			// data already written
			log
					.debug("Filter operating in unbuffered mode. Everything done, exiting");
			return;
		}

		// if you reach this point the PARAMETER_EXPORTING has been found, but
		// the special header has never been set in
		// response (this is the signal from table tag that it is going to write
		// exported data)
		log.debug("Filter operating in buffered mode. ");

		Map bean = (Map) request
				.getAttribute(TableTag.FILTER_CONTENT_OVERRIDE_BODY);

		if (log.isDebugEnabled()) {
			log.debug(bean);
		}

		Object pageContent = bean.get(TableTagParameters.BEAN_BODY);

		if (pageContent == null) {
			if (log.isDebugEnabled()) {
				log
						.debug("Filter is enabled but exported content has not been found. Maybe an error occurred?");
			}

			response.setContentType(wrapper.getContentType());
			PrintWriter out = response.getWriter();

			out.write(wrapper.getContentAsString());
			out.flush();
			out.close();
			return;
		}

		// clear headers
		if (!response.isCommitted()) {
			response.reset();
		}

		String filename = (String) bean.get(TableTagParameters.BEAN_FILENAME);
		String contentType = (String) bean
				.get(TableTagParameters.BEAN_CONTENTTYPE);

		if (StringUtils.isNotBlank(filename)) {
			response.setHeader("Content-Disposition", "attachment; filename=\""
					+ filename + "\"");
		}

		String characterEncoding = wrapper.getCharacterEncoding();
		String wrappedContentType = wrapper.getContentType();

		if (wrappedContentType != null
				&& wrappedContentType.indexOf("charset") > -1) {
			// charset is already specified (see #921811)
			characterEncoding = StringUtils.substringAfter(wrappedContentType,
					"charset=");
		}

		if (characterEncoding != null && contentType.indexOf("charset") == -1) //$NON-NLS-1$
		{
			contentType += "; charset=" + characterEncoding; //$NON-NLS-1$
		}

		response.setContentType(contentType);

		if (pageContent instanceof String) {
			// text content
			if (characterEncoding != null) {
				response.setContentLength(((String) pageContent)
						.getBytes(characterEncoding).length);
			} else {
				response
						.setContentLength(((String) pageContent).getBytes().length);
			}

			PrintWriter out = response.getWriter();
			out.write((String) pageContent);
			out.flush();
			out.close();
		} else {
			// dealing with binary content
			byte[] content = (byte[]) pageContent;
			response.setContentLength(content.length);
			OutputStream out = response.getOutputStream();
			out.write(content);
			out.flush();
			out.close();
		}
	}

	/**
	 * Do instantiate.
	 */
	private ExportDelegate() {
		// unused
	}
}
